package org.jugile.web2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.Properties;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.jugile.util.*;

public class VeloEngine extends Jugile {

	private VelocityContext ctx = null;
	private VelocityEngine ve = null;

    private static ThreadLocal<VeloEngine> veloEngine =
    	new ThreadLocal<VeloEngine>() {
    	protected synchronized VeloEngine initialValue() {
    		print("======= create new veloEngine");
    		VeloEngine v = new VeloEngine();
    		v.ve = new VelocityEngine();
    		try { 
                Properties p = new Properties();
                p.load(Jugile.getResource("velocity.properties"));
    			v.ve.init(p);
    			eval(v.ve, new VelocityContext(), new Blob(getMacroFilename()), true);
    		} catch (Exception e) { fail(e); }
    		print("======= veloengine created");
    		return v;
    	}
    };

    public static VeloEngine getVe() {
    	return veloEngine.get();
    }
    
	private VeloEngine() { 
		init();
	}
	public void init() { 
		ctx = new VelocityContext();
	}
    
	private static String getMacroFilename() {
		String fname = Props.get("jugile.web.macrofile");
		if (empty(fname)) return "/org/jugile/web2/components.vm";
		return fname;
	}
	
	public String eval(Blob b) { return eval(ve, ctx, b, true); }
	public String eval2(Blob b) { return eval(ve, ctx, b, false); }
	public Object getVar(String name) { return ctx.get(name); }
	public void setVar(String name, Object o) { ctx.put(name, o); }
	public void setVarEval(String name, String code) {
		Blob b = new Blob();
		b.append("#set($"+name+" = "+code+")");
		eval2(b);
	}
	
	private static String eval(VelocityEngine v, VelocityContext ctx, Blob b, boolean utf8) {
		ByteArrayInputStream bis = null;
		OutputStreamWriter osw = null;
		ByteArrayOutputStream bos = null;
		try {
			bis = new ByteArrayInputStream(b.getData());
			InputStreamReader isr = new InputStreamReader(bis, "UTF-8");
			bos = new ByteArrayOutputStream(16000);
			if (utf8) osw = new OutputStreamWriter(bos, "UTF-8");
			else osw = new OutputStreamWriter(bos);
			if (v != null) {
				if (ctx != null && osw != null && isr != null) 
					v.evaluate(ctx, osw, nn(b.getFilename(),"no-filename"), isr);
			}
	    	if (osw != null) osw.close();
	    	if (bos != null) bos.close();
	    	if (isr != null) isr.close();
	    	if (bis != null) bis.close();
	    	if (bos != null) return bos.toString();
		} catch (Exception e) {
			print("template eval failed: " + b.getFilename());
			e.printStackTrace();
			fail(e);
		} finally {
			if (osw != null) {
				try { osw.close(); } catch (Exception e) {}
			}
			if (bos != null) {
				try { bos.close(); } catch (Exception e) {}
			}
			if (bis != null) {
				try { bis.close(); } catch (Exception e) {}
			}
		}
		return null;
	}

	public void put(String key, Object o) { ctx.put(key, o); }
	public Object get(String key) { return ctx.get(key); }

}
